package org.convallaria.system.biz.service.impl;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.convallaria.system.biz.entity.SysUser;
import org.convallaria.system.biz.service.PasswordPolicyService;
import org.convallaria.system.biz.service.sys.SysUserService;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;

/**
 * 密码策略服务实现
 * 
 * @author convallaria
 * @since 1.0.0
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PasswordPolicyServiceImpl implements PasswordPolicyService {

    private final SysUserService sysUserService;
    private final RedisTemplate<String, String> redisTemplate;

    private static final String PASSWORD_HISTORY_PREFIX = "password:history:";
    private static final int PASSWORD_HISTORY_EXPIRE_DAYS = 365;

    // 常见密码列表
    private static final List<String> COMMON_PASSWORDS = Arrays.asList(
        "123456", "password", "123456789", "12345678", "12345",
        "1234567", "1234567890", "qwerty", "abc123", "111111",
        "123123", "admin", "letmein", "welcome", "monkey",
        "1234", "dragon", "master", "hello", "login"
    );

    // 特殊字符正则
    private static final Pattern SPECIAL_CHAR_PATTERN = Pattern.compile("[@$!%*?&]");
    // 小写字母正则
    private static final Pattern LOWERCASE_PATTERN = Pattern.compile("[a-z]");
    // 大写字母正则
    private static final Pattern UPPERCASE_PATTERN = Pattern.compile("[A-Z]");
    // 数字正则
    private static final Pattern DIGIT_PATTERN = Pattern.compile("\\d");

    @Override
    public PasswordValidationResult validatePassword(String password, Long userId) {
        if (password == null || password.trim().isEmpty()) {
            return PasswordValidationResult.failure("密码不能为空", PasswordPolicyViolation.TOO_SHORT);
        }

        PasswordPolicyConfig config = getPasswordPolicyConfig();

        // 1. 长度验证
        if (password.length() < config.getMinLength()) {
            return PasswordValidationResult.failure(
                String.format("密码长度不能少于%d位", config.getMinLength()),
                PasswordPolicyViolation.TOO_SHORT
            );
        }

        if (password.length() > config.getMaxLength()) {
            return PasswordValidationResult.failure(
                String.format("密码长度不能超过%d位", config.getMaxLength()),
                PasswordPolicyViolation.TOO_LONG
            );
        }

        // 2. 复杂度验证
        if (config.isRequireLowercase() && !LOWERCASE_PATTERN.matcher(password).find()) {
            return PasswordValidationResult.failure("密码必须包含小写字母", PasswordPolicyViolation.MISSING_LOWERCASE);
        }

        if (config.isRequireUppercase() && !UPPERCASE_PATTERN.matcher(password).find()) {
            return PasswordValidationResult.failure("密码必须包含大写字母", PasswordPolicyViolation.MISSING_UPPERCASE);
        }

        if (config.isRequireDigit() && !DIGIT_PATTERN.matcher(password).find()) {
            return PasswordValidationResult.failure("密码必须包含数字", PasswordPolicyViolation.MISSING_DIGIT);
        }

        if (config.isRequireSpecialChar() && !SPECIAL_CHAR_PATTERN.matcher(password).find()) {
            return PasswordValidationResult.failure("密码必须包含特殊字符(@$!%*?&)", PasswordPolicyViolation.MISSING_SPECIAL_CHAR);
        }

        // 3. 常见密码检查
        if (config.isCheckCommonPasswords() && isCommonPassword(password)) {
            return PasswordValidationResult.failure("密码过于简单，请使用更复杂的密码", PasswordPolicyViolation.COMMON_PASSWORD);
        }

        // 4. 用户名检查
        if (config.isCheckUsername() && userId != null) {
            SysUser user = sysUserService.getUserById(userId);
            if (user != null && password.toLowerCase().contains(user.getUserName().toLowerCase())) {
                return PasswordValidationResult.failure("密码不能包含用户名", PasswordPolicyViolation.CONTAINS_USERNAME);
            }
        }

        // 5. 个人信息检查
        if (config.isCheckPersonalInfo() && userId != null) {
            SysUser user = sysUserService.getUserById(userId);
            if (user != null) {
                // 检查是否包含真实姓名
                if (user.getRealName() != null && password.toLowerCase().contains(user.getRealName().toLowerCase())) {
                    return PasswordValidationResult.failure("密码不能包含真实姓名", PasswordPolicyViolation.CONTAINS_PERSONAL_INFO);
                }
                // 检查是否包含邮箱
                if (user.getEmail() != null && password.toLowerCase().contains(user.getEmail().toLowerCase())) {
                    return PasswordValidationResult.failure("密码不能包含邮箱", PasswordPolicyViolation.CONTAINS_PERSONAL_INFO);
                }
                // 检查是否包含手机号
                if (user.getPhoneNumber() != null && password.contains(user.getPhoneNumber())) {
                    return PasswordValidationResult.failure("密码不能包含手机号", PasswordPolicyViolation.CONTAINS_PERSONAL_INFO);
                }
            }
        }

        // 6. 历史密码检查
        if (isPasswordInHistory(password, userId)) {
            return PasswordValidationResult.failure(
                String.format("新密码不能与最近%d次使用的密码相同", config.getHistoryCount()),
                PasswordPolicyViolation.IN_HISTORY
            );
        }

        return PasswordValidationResult.success();
    }

    @Override
    public boolean isPasswordInHistory(String password, Long userId) {
        if (userId == null) {
            return false;
        }

        try {
            String historyKey = PASSWORD_HISTORY_PREFIX + userId;
            List<String> historyPasswords = redisTemplate.opsForList().range(historyKey, 0, -1);
            
            if (historyPasswords != null) {
                return historyPasswords.contains(password);
            }
            
            return false;
        } catch (Exception e) {
            log.error("检查密码历史失败", e);
            return false;
        }
    }

    @Override
    public boolean isCommonPassword(String password) {
        return COMMON_PASSWORDS.contains(password.toLowerCase());
    }

    @Override
    public PasswordPolicyConfig getPasswordPolicyConfig() {
        // TODO: 从配置中心或数据库获取密码策略配置
        // 这里返回默认配置
        PasswordPolicyConfig config = new PasswordPolicyConfig();
        config.setMinLength(8);
        config.setMaxLength(32);
        config.setRequireLowercase(true);
        config.setRequireUppercase(true);
        config.setRequireDigit(true);
        config.setRequireSpecialChar(true);
        config.setHistoryCount(5);
        config.setCheckCommonPasswords(true);
        config.setCheckUsername(true);
        config.setCheckPersonalInfo(true);
        
        return config;
    }

    /**
     * 记录密码到历史记录
     * 
     * @param password 密码
     * @param userId 用户ID
     */
    public void recordPasswordHistory(String password, Long userId) {
        if (userId == null) {
            return;
        }

        try {
            String historyKey = PASSWORD_HISTORY_PREFIX + userId;
            
            // 添加到历史记录
            redisTemplate.opsForList().leftPush(historyKey, password);
            
            // 保持历史记录数量限制
            PasswordPolicyConfig config = getPasswordPolicyConfig();
            redisTemplate.opsForList().trim(historyKey, 0, config.getHistoryCount() - 1);
            
            // 设置过期时间
            redisTemplate.expire(historyKey, java.time.Duration.ofDays(PASSWORD_HISTORY_EXPIRE_DAYS));
            
            log.info("记录用户 {} 密码历史", userId);
        } catch (Exception e) {
            log.error("记录密码历史失败", e);
        }
    }

    /**
     * 清除用户密码历史
     * 
     * @param userId 用户ID
     */
    public void clearPasswordHistory(Long userId) {
        if (userId == null) {
            return;
        }

        try {
            String historyKey = PASSWORD_HISTORY_PREFIX + userId;
            redisTemplate.delete(historyKey);
            log.info("清除用户 {} 密码历史", userId);
        } catch (Exception e) {
            log.error("清除密码历史失败", e);
        }
    }
}
